#include "../../include/lua/lua_package.h"
#include <string.h>
#include <stdlib.h>

namespace ZY {

    Lua::Lua(const string file)
    {
        link = lua_open();
        luaopen_base(link);
        luaopen_table(link);
        luaL_openlibs(link);
        luaopen_string(link);
        luaopen_math(link);

        int err = 0;
        err = luaL_loadfile(link, file.c_str());
        if( err ){
            cout<<"lua_openfile is failed"<<lua_tostring(link, -1)<<endl;
            return;
        }

        err = lua_pcall(link,0,0,0);
        if( err ){
            cout<<"lua_call is failed"<<lua_tostring(link, -1)<<endl;
            return;
        }

    }

    Lua::~Lua()
    {
        lua_close(link);
    }

    //int Lua::lua_init_call()
    //{
    //    int err = lua_pcall(link,0,0,0);
    //	if( err ){
    //		cout<<"lua_call is failed"<<lua_tostring(link, -1)<<endl;
    //		return -1;
    //	}
    //	return 0;
    //}

    void Lua::lua_set_ret( int num )
    {
        ret_list.clear();
        ret_num = num;
    }

    int Lua::lua_call_fun( const string func, string str[], int arg_num )
    {
        int err = 0;

        vector<string>::iterator iter;

        lua_getglobal(link, func.c_str() );

        for( int i = 0; i < arg_num; i++ ){
            lua_pushstring(link, str[i].c_str() );
        }

        err = lua_pcall(link,arg_num,ret_num,0);
        if( err ){
            cout<<"lua_call is failed"<<lua_tostring(link, -1)<<endl;
            return -1;
        }

        for( int i = -ret_num; i < 0; i++ ){
            ret_list.insert( ret_list.end(), lua_tostring(link, i )  );
        }
        lua_pop(link,ret_num );

        return 0;
    }

    vector<string>& Lua::lua_return_value()
    {
        return this->ret_list;
    }

	void Lua::lua_table_value()
	{
	    int it = lua_gettop( link );// 获取栈顶，此时Table肯定在栈顶
	    lua_pushnil( link );
	    ret_list.clear();                ///清除返回列表
	    if( LUA_TNIL == lua_type( link, it ) ){
	        cout<<"Lua file is not have the table!"<<endl;
	        return;
	    }
	    while( lua_next(link, it) )                         // 开始枚举，并把枚举到的值压入栈
	    {
	        if( lua_type( link, -1 ) ==  LUA_TTABLE ){
	            lua_table_value( );
	            continue;
	        }
	        ret_list.insert( ret_list.end(), lua_tostring(link, -1 )  );  // 得到Item的值并压入列表
	        lua_pop(link, 1);                              // 将Item从栈里面弹出
	    }
	    lua_pop(link, 1);
	}
	void Lua::lua_get_tablevalue( const string t_name )
	{
	    lua_getglobal( link, t_name.c_str() );    // 获取Table

        lua_table_value();
    }

    void Lua::lua_get_tablevalue( const string t_name, string index_str )
    {
         ret_list.clear();

        lua_getglobal( link, t_name.c_str( ) );     // 获取Table

        int it = lua_gettop( link );
        if( LUA_TNIL == lua_type( link, it ) ){
            cout<<"Lua file is not have the table!"<<endl;
            lua_pop( link, 1 );
            return;
        }

        lua_pushstring( link, index_str.c_str( ) );     // 指定要得到的是哪个Item


        lua_gettable( link, -2 );

        if( !lua_isnil( link, -1 ) ){
            if( lua_type( link, -1 ) == LUA_TTABLE ){
                lua_table_value();
            }else{
                ret_list.insert( ret_list.end(), lua_tostring( link, -1 ) );      // 获取Item的值，并将值压入列表
            }
        }
        lua_pop( link, 2 );                                    // 将Item和Table从栈里面弹出
    }

    void Lua::lua_get_tablevalue( const string t_name, int order )
    {
        ret_list.clear();    ///清除返回列表

        lua_getglobal( link, t_name.c_str( ) );     // 获取Table

        int it = lua_gettop( link );
        if( LUA_TNIL == lua_type( link, it ) ){
            cout<<"Lua file is not have the table!"<<endl;
            lua_pop( link, 1 );
            return;
        }

        lua_pushnumber( link, order );     // 指定要得到的是哪个Item
        lua_gettable( link, -2 );


        if( !lua_isnil( link, -1 ) ){
            if( lua_type( link, -1 ) == LUA_TTABLE ){
                lua_table_value();
            }else{
                ret_list.insert( ret_list.end(), lua_tostring( link, -1 ) );      // 获取Item的值，并将值压入列表
            }
        }
        lua_pop( link, 1 );                                    // 将Item和Table从栈里面弹出

    }

    void Lua::lua_set_tablevalue( const string t_name, const string index_str, string value )
    {
        lua_getglobal( link, t_name.c_str( ) );     // 获取Table

        int it = lua_gettop( link );
        if( LUA_TNIL == lua_type( link, it ) ){
            lua_newtable( link );
            lua_pushstring( link, index_str.c_str() );
            lua_pushstring( link, value.c_str() );
            lua_settable( link, -3 );
            lua_setglobal( link, t_name.c_str( ) );
            lua_pop( link, 1 );
            return;
        }

        lua_pushstring( link, value.c_str() );

        lua_setfield( link, -2, index_str.c_str() );

        lua_pop( link, 1 );
    }

    void Lua::lua_set_tablevalue( const string t_name, int order, string value )
    {
        lua_getglobal( link, t_name.c_str( ) );     // 获取Table

        int it = lua_gettop( link );
        if( LUA_TNIL == lua_type( link, it ) ){
            lua_newtable( link );
            lua_pushstring( link, value.c_str() );
            lua_rawseti( link, -2, order );
            lua_setglobal( link, t_name.c_str( ) );
            lua_pop( link, 1 );
            return;
        }

        lua_pushstring( link, value.c_str() );

        lua_rawseti( link, -2, order );

        lua_pop( link, 1 );
    }

    void Lua::lua_set_tablevalue( const string t_name, string value )
    {
        int num = 0;
        lua_getglobal( link, t_name.c_str() );

        int top = lua_gettop( link );
        lua_pushnil( link );

        if( LUA_TNIL != lua_type( link, top ) ){

            while( lua_next(link, top) )                         // 开始枚举，并把枚举到的值压入栈
            {
                num++;
                lua_pop(link, 1);                              // 将Item从栈里面弹出
            }
        }
        lua_pop( link, 1 );
        lua_set_tablevalue( t_name.c_str(), num+1, value.c_str() );
    }

    void Lua::lua_table_save( char *buf )
    {
        char tmp_buf[128];
        string tmp_key, tmp_value;
        int it = lua_gettop( link );// 获取栈顶，此时Table肯定在栈顶
        lua_pushnil( link );
        ret_list.clear();                ///清除返回列表
        if( LUA_TNIL == lua_type( link, it ) ){
            cout<<"Lua file is not have the table!"<<endl;
            return;
        }
        while( lua_next(link, it) )                         // 开始枚举，并把枚举到的值压入栈
        {
            if( lua_type( link, -1 ) ==  LUA_TTABLE ){
                strcat( buf, "\t{\n" );
                lua_table_save( buf );

                buf[strlen(buf)-1] = '\t';
                buf[strlen(buf)-2] = '\n';
                buf[strlen(buf)] = '}';
                strcat( buf, ",\n" );
                continue;
            }
            bzero( tmp_buf, sizeof( tmp_buf ) );
            tmp_value = lua_tostring(link, -1 );
            lua_pop(link, 1);
            switch( lua_type( link, -1 ) ){     // 将Item从栈里面弹出

                case LUA_TSTRING:
                    tmp_key = lua_tostring(link, -1 );
                    sprintf( tmp_buf, "\t%s = \\\"%s\\\",\n", tmp_key.c_str(), tmp_value.c_str() );
                    break;
                case LUA_TNUMBER:
                    sprintf( tmp_buf, "\t\\\"%s\\\",\n", tmp_value.c_str() );
                    break;
                default:
                    break;
            }
            strcat( buf, tmp_buf );
        }

        lua_pop(link, 1);
    }

    void Lua::lua_save_tablevalue( const string file_name, const string t_name )
    {
        char buff[10240];
        char allbuff[10248];

        bzero( buff, sizeof( buff ) );

        sprintf( buff, "%s = {\n", t_name.c_str() );
        lua_getglobal( link, t_name.c_str() );
        lua_table_save( buff );

        buff[strlen(buff)-1] = '}';
        buff[strlen(buff)-2] = '\n';
        strcat( buff, "\n" );
        sprintf( allbuff, "echo \"%s\" > %s", buff, file_name.c_str() );

        system( allbuff );

    }
};
